package com.app.protocol;

import com.app.exception.GPSDataVertifyFailException;
import soft.common.*;
import soft.ifs.IByteBuff;
import soft.ifs.IBytesBuild;
import soft.ifs.IParse;
import soft.ifs.IParseBuild;
import soft.net.exception.DataIsNullException;
import soft.net.exception.DecodeDataFailException;
import soft.net.model.AReadNetStream;
import soft.net.model.CusByteStream;

import java.util.Date;

/**
 * 锁操作指令
 * <p>
 * 锁操作指令（1B, 0x15）+ Cmd（1B）+LockID(4B)+Gate（1B）+ Bill (8B)+ LineCode(2B) + Key(6B)+
 * Target（1B）+ Time (4B) +绝对时间（6B）
 * <p>
 * <p>
 * <p>
 * 地址 功能代码 子功能长度 数据长度 业务数据 子功能（当子功能长
 * 度!=0 时才有）
 * CRC
 * 0x81 0x2D 0x03（带指令
 * 序列号）/0x00
 * （不带指令序
 * 列号）
 * DD 0x2A(业务头)
 * ......（具体业务数
 * 据，具体见下面）
 * 0x23(业务尾)
 * 0x01 （表示需要
 * 终端通信确认）/
 * 0x03（表示不需要
 * 终端通信确认）
 * 0xBBBB(指令序
 * 列号)
 *
 * @author fanpei
 */

/**
 * @author fanpei
 */
public class ProtocolLockInfo extends AReadNetStream implements IParse, IBytesBuild {
    public static final byte STARTFLAG = (byte) 0x2A;
    public static final byte ENDFLAG = (byte) 0x23;
    /**
     * 大小固定为31字节
     */
    public final static int UP_SIZE = 31;


    public final static int DOWN_SIZE = 39;
    private static final long GMT_TIMESTAMP_From2008_3_18 = 1205769600000L;// 距离 2008-3-18 00:00:00时间差

    private int lockDevID;// 锁ID
    /**
     * (1) 锁操作指令 0x15
     *
     * @Size 1个字节
     */
    private byte lockOpr = 0x15;

    /**
     * (2) 具体操作命令字 |检查锁状态 0x1 |  设置动态密码 0xA0 |施封 远程施封：0x32|解封 远程解封0x38  |解除报警 远程解除报警 0x42|远程读取：0x48
     *
     * @Size 1个字节
     */
    private byte cmd;

    /**
     * (3-6) 电子锁编号
     *
     * @Size 4 个字节
     */
    private byte[] lockdevIDs;

    /**
     * (7) 通道号 卡口的通道号（如通道 15 即为 0x0F），中心下
     * 发通道号固定为 0x00，
     *
     * @Size 1 个字节
     */
    private byte gate = 0x00;


    /**
     * (8-15) 载货清单号
     *
     * @Size 8 个字节
     */
    private byte[] bill = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    /**
     * (8) 电压：1 个字节
     */
    private byte voltage;

    private byte ver;

    /**
     * (9) 锁当前状态：1 个字节,只对上传信息有效(见附录 3)，下行时，此位保
     * 留使用，填 0x00
     */
    private byte lockStatus;

    /**
     * (10) 锁:表示当前电机是否已经将锁锁定（测试时使
     * 用，正常使用时候不解析）,直接显示即可，不
     * 解析。
     * 只对上传信息有效，下行时，此位保留使用，
     * 填 0x00
     */
    private byte motoStatus;

    /**
     * ，操作源：短信 0x00,自动 0x01,键盘 0x02,手持机 0X03；
     * 中心 0X04；卡口 0X05；
     */
    private byte cmdSRC;
    /**
     * (16-17) 线路编号（将数字 10 进制值转为 2 字节 16 进
     * 制）备用，下发写死全 0 即可
     *
     * @Size 2 个字节
     */
    private byte[] lineCode = {0x00, 0x00};

    /**
     * (18-23) 密钥
     *
     * @dsrc 作为电子封条在施封时写入电子锁，解封时电
     * 子锁比对解封指令中包含的信息钥匙与自身存储电子封条是否相符，相符则解除电子封条，
     * 否则失败。
     * 1.RF 锁：将前 4 位数字 10 进制值分别转换为
     * 2B 的 16 进制，后 6 位数字的 10 进制值转换为
     * 4B 的 16 进制，下同）
     * 2.键盘密码锁：直接 6 位 ASCII 码数字 090005
     * 3.其他锁: 随意，施封解封保持一致即可
     * @Size 6 个字节
     */
    private byte[] key;

    /**
     * (24)操作对象
     *
     * @dsrc GPS 锁：写死 0X0
     * @Size 1 个字节
     */
    private byte target = 0x00;


    /**
     * (25-28) 相对时间
     *
     * @Size 4 个字节
     */
    private byte[] time = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    /**
     * (29-35) 指令发送时间
     *
     * @Size 6 个字节
     */
    private byte[] sendtime;

    private byte[] srcBytes;// 解析用变量

    public byte getVer() {
        return ver;
    }

    public void setVer(byte ver) {
        this.ver = ver;
    }

    /**

     * default constructor
     */
    public ProtocolLockInfo() {
        objinit();
    }

    /**
     * parse constructor
     *
     * @param srcBytes 原始bytes
     */
    public ProtocolLockInfo(byte[] srcBytes) {
        objinit();
        this.srcBytes = srcBytes;
    }


    public byte getVoltage() {
        return voltage;
    }

    public void setVoltage(byte voltage) {
        this.voltage = voltage;
    }

    public byte getLockStatus() {
        return lockStatus;
    }

    public void setLockStatus(byte lockStatus) {
        this.lockStatus = lockStatus;
    }

    public byte getMotoStatus() {
        return motoStatus;
    }

    public void setMotoStatus(byte motoStatus) {
        this.motoStatus = motoStatus;
    }

    public byte getCmdSRC() {
        return cmdSRC;
    }

    public void setCmdSRC(byte cmdSRC) {
        this.cmdSRC = cmdSRC;
    }

    public byte getLockOpr() {
        return lockOpr;
    }

    public void setLockOpr(byte lockOpr) {
        this.lockOpr = lockOpr;
    }

    public byte getCmd() {
        return cmd;
    }

    public void setCmd(byte cmd) {
        this.cmd = cmd;
    }

    public byte[] getLockdevIDs() {
        return lockdevIDs;
    }

    public void setLockdevIDs(byte[] lockdevIDs) {
        this.lockdevIDs = lockdevIDs;
    }

    public byte getGate() {
        return gate;
    }

    public void setGate(byte gate) {
        this.gate = gate;
    }


    public byte[] getBill() {
        return bill;
    }

    public void setBill(byte[] bill) {
        this.bill = bill;
    }

    public byte[] getLineCode() {
        return lineCode;
    }

    public void setLineCode(byte[] lineCode) {
        this.lineCode = lineCode;
    }

    public byte[] getKey() {
        return key;
    }

    public void setKey(byte[] key) {
        this.key = key;
    }

    public byte getTarget() {
        return target;
    }

    public void setTarget(byte target) {
        this.target = target;
    }


    public byte[] getTime() {
        return time;
    }

    public void setTime(byte[] time) {
        this.time = time;
    }

    public byte[] getSendtime() {
        return sendtime;
    }

    public void setSendtime(byte[] sendtime) {
        this.sendtime = sendtime;
    }

    /**
     * 对象初始化
     */
    private void objinit() {
        lockdevIDs = new byte[4];
        bill = new byte[8];
        lineCode = new byte[2];
        key = new byte[6];
        time = new byte[4];
        sendtime = new byte[6];
    }

    /**
     * 数据校验
     */
    public void validate() {


    }

    @Override
    public void parse() throws DecodeDataFailException, DataIsNullException {
        if (srcBytes == null || srcBytes.length == 0) {
            throw new DataIsNullException("ProtocolLockInfo parse:srcBytes is null or empty!");
        } else {
            System.out.println("ProtocolLockInfo:" + BytesHexStrTranslate.bytesToHexFun1(srcBytes));
        }
        IByteBuff in = null;
        try {
            in = new CusByteStream(srcBytes);


//            操作回复（1B,回复 0x55）+Cmd（1B）+LockID(4B)+Gate（1B）+ Voltage(1B)+LockStatus（1B）
//            + MotoStatus (1B)+ Time (4B)+Ver (1B) +绝对时间（6B）
//            开始    操作回复   Cmd  LockID     Gate       Voltage  LockStatus    MotoStatus  Time             Ver    绝对时间       结束  子功能  子功能
//            2A      55       62   06CB042C   04          37      50            02          14546EC9         03     190107154826 2303810200
            if (in.readableBytes() == UP_SIZE-4) {
                if (STARTFLAG != in.readByte()) {
                    throw new DecodeDataFailException(StringUtil.getMsgStr("data not startwith：{}", STARTFLAG));
                }
                
                lockOpr = in.readByte();
                cmd = in.readByte();
                in.readBytes(lockdevIDs);
                gate = in.readByte();
//                in.readBytes(bill);
                voltage = in.readByte();
                lockStatus = in.readByte();
                motoStatus = in.readByte();
                in.readBytes(time);
                ver = in.readByte();
//                cmdSRC = in.readByte();
                in.readBytes(sendtime);
            }


//            （1B,0x55）+ Cmd（1B）+LockID(4B)+Gate（1B）+ Bill (8B)+ Voltage(1B)+LockStatus
//（1B）+ MotoStatus (1B)+ cmdSRC(1B，操作源：短信 0x00,自动 0x01,键盘 0x02,手持机 0X03；
//                    中心 0X04；卡口 0X05；)+绝对时间（6B）
            if (in.readableBytes() == UP_SIZE) {
                if (STARTFLAG != in.readByte()) {
                    throw new DecodeDataFailException(StringUtil.getMsgStr("data not startwith：{}", STARTFLAG));
                }
                lockOpr = in.readByte();
                cmd = in.readByte();
                in.readBytes(lockdevIDs);
                gate = in.readByte();
                in.readBytes(bill);
                voltage = in.readByte();
                lockStatus = in.readByte();
                motoStatus = in.readByte();
                cmdSRC = in.readByte();
                in.readBytes(sendtime);
            }


        } finally {
            if (in != null) {
                in.release();
            }
        }
        clear();

        lockDevID = BConvrtUtil.byteToInt(lockdevIDs);
    }

    @Override
    public void clear() {
        srcBytes = null;
    }


    @Override
    public byte[] buildBytes() throws Exception {
        byte[] sends = new byte[DOWN_SIZE];
        sends[0] = STARTFLAG;
        sends[1] = lockOpr;
        sends[2] = cmd;
        System.arraycopy(lockdevIDs, 0, sends, 3, 4);
        sends[7] = gate;
        System.arraycopy(bill, 0, sends, 8, 8);
        System.arraycopy(lineCode, 0, sends, 16, 2);
        System.arraycopy(key, 0, sends, 18, 6);
        sends[24] = target;
        System.arraycopy(time, 0, sends, 25, 4);
        System.arraycopy(sendtime, 0, sends, 29, 6);
        sends[35] = ENDFLAG;
        sends[36] = 0x03;
        sends[37] = (byte) 0xBB;
        sends[38] = (byte) 0xBB;
        return sends;
    }
}
